package com.lg.java.reference;

import com.lg.domain.User;

import java.lang.ref.*;
import java.util.concurrent.TimeUnit;

/**
 强：只要还有引用，永远不会被垃圾回收收回
 软：垃圾回收时，当内存充足的时候不会被收回，内存不足是会被收回
 弱：垃圾回收时，不管内存是否充足都会被收回
 虚：什么时候都没有，要配合引用队列使用 referenceQueue使用


 -XX:+PrintGCDetails -Xms1024m -Xmx1024m -Xss1024k -XX:MetaspaceSize=1024m -XX:SurvivorRatio=4  -XX:MaxTenuringThreshold=13
 */
public class ReferenceTest {
    public static void main(String[] args) throws InterruptedException {
//        strong();
//        soft();
//        soft2();
        weak();
//        phantom();

        /**
         * DirectByteBuffer  cleaner
         */
    }

    /**
     * 强：只要还有引用，永远不会被垃圾回收收回
     */
    private  static  void strong(){
        Integer reference = 11;
        System.out.println("start "+reference);

        System.gc();
        System.out.println("head gc " +reference);

        try {
            notEnough();
        } catch (Exception e) {

        }finally {
            System.out.println("gc "+ reference);
        }
    }

    /**
     *  软：垃圾回收时，当内存充足的时候不会被收回，内存不足是会被收回
     */
    private  static  void soft(){
        Object reference = new Object();
        ReferenceQueue<Object> objectReferenceQueue = new ReferenceQueue<>();
        SoftReference<Object> integerSoftReference = new SoftReference<>(reference,objectReferenceQueue);
        System.out.println("start "+reference);
        System.out.println("start "+integerSoftReference.get());
        System.out.println("start "+objectReferenceQueue.poll());

        reference = null;
        System.gc();
        System.out.println("head gc "+reference);
        System.out.println("head gc "+integerSoftReference.get());
        System.out.println("head gc "+objectReferenceQueue.poll());
        try {
            notEnough();
        } catch (Exception e) {

        }finally {
            System.out.println("gc "+reference);
            System.out.println("gc "+integerSoftReference.get());
            System.out.println("gc "+objectReferenceQueue.poll());
        }
    }

    private  static  void soft2() throws InterruptedException {
        User reference = new User();
        ReferenceQueue<User> objectReferenceQueue = new ReferenceQueue<>();
        SoftReference<User> integerSoftReference = new SoftReference<>(reference,objectReferenceQueue);
        System.out.println("start "+reference);
        System.out.println("start "+integerSoftReference.get());
        System.out.println("start "+objectReferenceQueue.poll());

        reference = null;
        System.gc();
        System.out.println("head gc "+reference);
        System.out.println("head gc "+integerSoftReference.get());
        System.out.println("head gc "+objectReferenceQueue.poll());
        try {
            notEnough();
        } catch (Exception e) {

        }finally {
            TimeUnit.SECONDS.sleep(22);
            System.out.println("gc "+reference);
            System.out.println("gc "+integerSoftReference.get());
            System.out.println("gc "+objectReferenceQueue.poll());
        }
    }

    /**
     * 弱：垃圾回收时，不管内存是否充足都会被收回
     */
    private  static  void weak() throws InterruptedException {
        Object reference = new Object();
        ReferenceQueue<Object> objectReferenceQueue = new ReferenceQueue<>();
        WeakReference<Object> integerSoftReference = new WeakReference<>(reference,objectReferenceQueue);
        System.out.println("start "+reference);
        System.out.println("start "+integerSoftReference.get());
        System.out.println("start "+objectReferenceQueue.poll());

        reference = null;
        System.gc();
        //确保gc完成
        TimeUnit.SECONDS.sleep(1);

        TimeUnit.SECONDS.sleep(2);
        System.out.println("head gc "+reference);
        System.out.println("head gc "+integerSoftReference.get());
        Reference<?> poll = objectReferenceQueue.poll();
        System.out.println("head gc "+poll);
        System.out.println("加入队列中的是这个弱引用--> "+( poll == integerSoftReference));

    }

    /**
     *  虚：什么时候都没有，要配合引用队列使用 referenceQueue使用
     *
     *  referenceQueue
     *  第一次gc 不会把对象回收 二十放到了referenceQueue中，第二次gc才会收回
     *  当gc（垃圾回收线程）准备回收一个对象时，如果发现它还仅有软引用(或弱引用，或虚引用)指向它，
     *  就会在回收该对象之前，把这个软引用（或弱引用，或虚引用）加入到与之关联的引用队列（ReferenceQueue）中，
     *  如果一个软引用（或弱引用，或虚引用）对象本身在引用队列中，就会直接被回收
     *
     *  如果这个引用没有关联引用队列，则直接被回收
     */
    private  static  void phantom(){
        Object reference = new Object();
        ReferenceQueue<Object> objectReferenceQueue = new ReferenceQueue<>();
        PhantomReference<Object> integerSoftReference = new PhantomReference<>(reference,objectReferenceQueue);
        System.out.println("start "+reference);
        System.out.println("start "+integerSoftReference.get());
        System.out.println("start " + objectReferenceQueue.poll());

        reference = null;
        System.gc();
        System.out.println("head gc "+reference);
        System.out.println("head gc "+integerSoftReference.get());
        System.out.println("head gc " + objectReferenceQueue.poll());
        try {
            notEnough();
        } catch (Exception e) {

        }finally {
            System.out.println("gc "+reference);
            System.out.println("gc "+integerSoftReference.get());
            System.out.println("gc " + objectReferenceQueue.poll());
        }
    }

    private static void  notEnough() {
        byte[] bytes = new byte[1024 * 1024 * 1024];
    }
}
